// 传统的构造函数的问题
// 1. 属性和原型方法定义分离,降低了可读性
// 2. 原型成员可以被枚举
// 3. 默认情况下,构造函数仍然可以被当作普通函数使用
(function () {
  return;
  // 面向对象中, 将下面对一个对象的所有成员的定义,统称为类
  // 构造函数 构造器
  function Animal(type, name, age, sex) {
    this.type = type;
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  // 中间可能存在别的代码, 逻辑上分开了
  // 定义实例方法(原型方法)
  Animal.prototype.print = function () {
    console.log(`[种类]:${this.type}`);
    console.log(`[名字]:${this.name}`);
    console.log(`[年龄]:${this.age}`);
    console.log(`[性别]:${this.sex}`);
  };

  const a = new Animal("狗", "旺财", "19", "男");

  // 原型成员可以被枚举
  for (const key in a) {
    console.log(key); // 其中print会出现
  }
})();
// ======================================================

// 类的特点
// 1. 类声明不会被提升, 与let和const一样,存在暂时性死区
// 2. 类中的所有代码均在严格模式下执行
// 3. 类的所有方法都是不可枚举的
// 4. 类的所有方法都无法被当作构造函数使用
// 5. 类的构造器必须使用new 来调用
(function () {
  // return
  class Animal {
    constructor(type, name, age, sex) {
      this.type = type;
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    // 这里就是原型方法
    print() {
      console.log(`[种类]:${this.type}`);
      console.log(`[名字]:${this.name}`);
      console.log(`[年龄]:${this.age}`);
      console.log(`[性别]:${this.sex}`);
    }
  }
  const a = new Animal("狗", "旺财", "19", "男");
  a.print();

  for (const key in a) {
    console.log(key); // 自动把原型设置为不可枚举
  }
})();
